我听过 Herb Sutter 最近的一次演讲,他认为过去std::vector和过去std::string的理由const &基本上已经不复存在了。他建议现在最好编写如下函数:
std::vector
std::string
const &
std::string do_something ( std::string inval ) { std::string return_val; // ... do stuff ... return return_val; }
我知道return_val在函数返回时这将是一个右值,因此可以使用非常便宜的移动语义返回。但是,inval仍然比引用的大小(通常实现为指针)大得多。这是因为 astd::string具有各种组件,包括指向堆的指针和char[]用于短字符串优化的成员。所以在我看来,通过引用传递仍然是一个好主意。
return_val
inval
char[]
谁能解释为什么 Herb 会这么说?
赫布之所以这么说,就是因为这样的案例。
假设我有调用函数的A函数B,它调用函数C。并将A一个字符串传递B到C. A不知道也不关心C;众所周知A的是B。也就是说,C是 的实现细节B。
A
B
C
假设 A 定义如下:
void A() { B("value"); }
如果 B 和 C 取字符串 by const&,那么它看起来像这样:
const&
void B(const std::string &str) { C(str); } void C(const std::string &str) { //Do something with `str`. Does not store it. }
一切都很好。你只是在传递指针,没有复制,没有移动,每个人都很开心。C需要 aconst&因为它不存储字符串。它只是使用它。
现在,我想做一个简单的改变:C需要将字符串存储在某个地方。
void C(const std::string &str) { //Do something with `str`. m_str = str; }
你好,复制构造函数和潜在的内存分配。C++11 的移动语义应该可以消除不必要的复制构造,对吧?并A通过一个临时的;没有理由C必须 复制 数据。它应该带着给它的东西潜逃。
除非它不能。因为它需要一个const&.
如果我更改C为按值获取其参数,那只会导致B复制到该参数中;我一无所获。
因此,如果我只是str通过所有函数按值传递,依靠std::moveshuffle 数据,我们就不会有这个问题。如果有人想坚持下去,他们可以。如果他们不这样做,哦,好吧。
str
std::move
它更贵吗?是的; 移动到一个值比使用引用更昂贵。它比副本便宜吗?不适用于带有 SSO 的小字符串。值得做吗?
这取决于您的用例。你有多讨厌内存分配?